home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
VIVIDUS
/
QD3D.SIT
/
qd3d
/
geometry.c
< prev
next >
Wrap
Text File
|
1991-10-09
|
5KB
|
252 lines
/* ======================================================================
Supplemental geometry routines.
This is part of the qd3d Vividus Source Code Library. See the
extern qd3d.doc documentation file for usage. See individual
routines for routine documentation.
Copyright 1991 by Vividus Consulting.
This is not public domain source code. You may not copy and
paste from this source code. Read your Vividus Licensing
agreement for details and other restrictions.
Note: At present, these routines are only supported as needed by
hedra.
====================================================================== */
#include <math.h>
#include <vect.h>
#include <vect.g>
#include "geometry.h"
static double twoPI = 6.283185307179586477;
static double halfPI = 1.570796326794896619;
static double two = 2.0;
static double four = 4.0;
static double zerop = .000001; /* Zero on the positive side */
static double
DizzyAngle(
vector *a,
int plane);
static double
DizzyDelta(
double b,
double a);
/* ====================================================================== */
#define yzPlane 0
#define xzPlane 1
#define xyPlane 2
Boolean
PtInPoly(
vector *pt, /* Point on poly plane to see if in poly. */
int n, /* Number of verts in poly. */
vector verts[], /* Vertices of polygon. */
vector *norm) /* Normal of polygon. */
/*
Returns true if the point (presumably already on the plane of the
polygon is in the polygon.
Note:
This only works if the polygon is planar.
The intersection of the ray with the poly plane must already
be found.
*/
{
vector a;
double theta = 0.0;
double thetasum = 0.0;
double thetanew;
double theta0;
int i;
int orientation;
if (norm->z > norm->y) {
if (norm->z > norm->x)
orientation = xyPlane;
else
orientation = yzPlane;
} else {
if (norm->y > norm->x)
orientation = xzPlane;
else
orientation = yzPlane;
}
vvect(pt, &verts[0], &a);
theta = theta0 = DizzyAngle(&a, orientation);
for (i = 1; i < n; i++) {
vvect( pt, &verts[i], &a);
thetanew = DizzyAngle(&a, orientation);
thetasum += DizzyDelta(thetanew, theta);
theta = thetanew;
}
thetasum += DizzyDelta(theta0, theta);
if ( (thetasum > PI) || (thetasum < -PI) )
return(true);
else
return(false);
}
Boolean
RayXPlane(
Ray *r,
Plane *p,
double *t,
vector *pt)
/*
Returns true if the ray intersects the plane and the point and paramter of
the intersections.
*/
{
vector v;
vsub(&p->pt, &r->b, &v);
*t = vdot(&r->m, &p->normal);
if (*t == 0.0)
return(false);
*t = vdot(&v, &p->normal)/(*t);
vscale(*t, &r->m, &v);
vadd(&v, &r->b, pt);
return(true);
}
int
RayXEllipsoid(
Ray *r,
Ellipsoid *e,
double *t)
/*
Returns false if there isn't an intersection. If there is, the number of
intersections is returned; ed, eb, &t reflect the point, normal, & t of the ray.
Note: Intersections can only occur with positive values of t.
Warning: Presently the only ellipsoid supported is a sphere.
*/
{
/* double a = r->m.x * r->m.x + r->m.y * r->m.y + r->m.z * r->m.z; */
double a = 1.0; /* rm is a unit vector. */
double b = two * r->m.x * (r->b.x - e->center.x) +
two * r->m.y * (r->b.y - e->center.y) +
two * r->m.z * (r->b.z - e->center.z);
double c = e->center.x * e->center.x +
e->center.y * e->center.y +
e->center.z * e->center.z +
r->b.x * r->b.x + r->b.y * r->b.y + r->b.z * r->b.z -
two * ( e->center.x * r->b.x +
e->center.y * r->b.y +
e->center.z * r->b.z) -
e->dimensions.x * e->dimensions.x;
double d = b * b - four * a * c;
double t1, t2;
vector p1, p2;
int retval = 0;
if (d < 0.0)
return (retval);
if (d == 0.0) {
t1 = -b / (two * a);
if (t1 > zerop)
retval = 1;
} else {
t1 = (- b - sqrt(d))/(two * a);
t2 = (- b + sqrt(d))/(two * a);
if (t1 > zerop)
retval = 2;
else {
if (t2 > zerop)
retval = 1;
else
return(0);
}
}
/* t1 (if it is +) must be the closer root */
if (retval == 1)
*t = t2; /* t1 was negative. */
else
*t = t1;
return (retval);
}
void
EllipsoidFromBox(Bound3dBox *bb, Ellipsoid *e)
/*
Finds the smallest ellipsoid containing the box. The ellipsoid is
centered about the box.
Note: Presently only spherical ellipsoids are created.
*/
{
vector a;
double s = 1.0/2.0;
vadd(&bb->max, &bb->min, &a);
vscale(s, &a, &e->center);
s = vdist(&e->center, &bb->max);
vscale(s, &vone, &e->dimensions);
}
/* ====================================================================== */
static double
DizzyAngle(
vector *a,
int plane)
/*
Returns the dizzy angle.
*/
{
switch(plane) {
case yzPlane:
return(atan2(a->y, a->z));
case xzPlane:
return(atan2(a->x, a->z));
case xyPlane:
return(atan2(a->x, a->y));
}
}
static double
DizzyDelta(
double b,
double a)
/*
deltat theta from angle a to angle b.
Note this returns a value between -╣ and ╣. It is necessary for when the vertices
"wrap around" the -╣, ╣ boundary.
*/
{
double dt = b - a;
#if 1 /* Should be turned off once we're sure -╣ <= atan2 <= ╣ */
if ((a > PI) || (a < -PI) || (b < -PI) || (b > PI))
DebugStr("\pdizzydelta domain error");
#endif
if (dt > PI)
dt -= twoPI;
if (dt < -PI)
dt += twoPI;
return(dt);
}